#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 10

void set_non_blocking(int sock)
{
    int opts;
    
    opts = fcntl(sock, F_GETFL);
    if (opts < 0)
    {
        perror("fcntl getfl error");
        exit(1);
    }

    opts = opts|O_NONBLOCK;
    if (fcntl(sock, F_SETFL, opts) < 0)
    {
        perror("fcntl setfl error");
        exit(1);
    }
}

int main(int argc, char *argv[])
{
    int listenfd, epfd, connfd, nfds, i, sockfd, n;
    struct sockaddr_in serveraddr;
    struct epoll_event ev, events[20];
    char line[MAXLINE] = "123456789";


    epfd = epoll_create(256);
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    set_non_blocking(listenfd);
    
    ev.data.fd = listenfd;
    ev.events = EPOLLIN|EPOLLET; 
    epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);

    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    inet_aton("127.0.0.1", &serveraddr.sin_addr);
    serveraddr.sin_port = htons(5555);

    if (bind(listenfd, (struct sockaddr *)&serveraddr, 
            sizeof(serveraddr)) < 0)
    {
        perror("bind error");
        exit(1);
    }

    if (listen(listenfd, 20) < 0)
    {
        perror("listen error");
        exit(1);
    }

    for (;;) 
    {
        nfds = epoll_wait(epfd, events, 20, 500);
        for (i = 0; i < nfds; ++i)
        {
            if (events[i].data.fd == listenfd)
            {
                connfd = accept(listenfd, NULL, NULL);
                if (connfd < 0)
                {
                    perror("accept error");
                    exit(1);
                }

                set_non_blocking(connfd);
                ev.data.fd = connfd;
                ev.events = EPOLLIN|EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);

            }
            else if (events[i].events & EPOLLIN)
            {
                sockfd = events[i].data.fd; 
                if (sockfd < 0)
                    continue;

                n = read(sockfd, line, MAXLINE);
                if (n < 0)
                {
                    if (errno == ECONNRESET)
                    {
                        close(sockfd);
                        events[i].data.fd = -1;
                    }
                    else
                        perror("read error");
                }
                else if (n == 0)
                {
                    close(sockfd);
                    events[i].data.fd = -1;
                }

                ev.data.fd = sockfd;
                ev.events = EPOLLOUT|EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);

            }
            else if (events[i].events & EPOLLOUT)
            {
                sockfd = events[i].data.fd;
                write(sockfd, line, n);
                ev.data.fd = sockfd;
                ev.events = EPOLLIN|EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
            }
        }
    
    }

    return 0;
}
